package com.mysiteforme.admin.service.system.systemimpl;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.mysiteforme.admin.dao.system.UserDao;
import com.mysiteforme.admin.entity.Role;
import com.mysiteforme.admin.entity.User;
import com.mysiteforme.admin.service.system.UserService;
import com.mysiteforme.admin.util.other.ToolUtil;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Map;
import java.util.Set;
/**
 *  服务实现类
 */
@Service("userService")
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService {

	/* 这里caching不能添加put 因为添加了总会执行该方法
	 * @see com.mysiteforme.service.UserService#findUserByLoginName(java.lang.String)
	 * Cacheable 主要针对方法配置，能够根据方法的请求参数对其结果进行缓存
	 */
	@Cacheable(value = "user", key = "'user_name_'+#name",unless = "#result == null")
	@Override
	public User findUserByLoginName(String name) {
		// TODO Auto-generated method stub
		Map<String,Object> map = Maps.newHashMap();
		map.put("loginName", name);
		User u = baseMapper.selectUserByMap(map);
		return u;
	}


	@Cacheable(value = "user",key="'user_id_'+T(String).valueOf(#id)",unless = "#result == null")
	@Override
	public User findUserById(Long id) {
		// TODO Auto-generated method stub
		Map<String,Object> map = Maps.newHashMap();
		map.put("id", id);
		return baseMapper.selectUserByMap(map);
	}

	@Override
	@Caching(put = {
			@CachePut(value = "user", key = "'user_id_'+T(String).valueOf(#result.id)",condition = "#result.id != null and #result.id != 0"),
			@CachePut(value = "user", key = "'user_name_'+#user.loginName", condition = "#user.loginName !=null and #user.loginName != ''"),
			@CachePut(value = "user", key = "'user_email_'+#user.email", condition = "#user.email != null and #user.email != ''"),
			@CachePut(value = "user", key = "'user_tel_'+#user.tel", condition = "#user.tel != null and #user.tel != ''")
	})
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public User saveUser(User user) {
		ToolUtil.entryptPassword(user);
		user.setLocked(false);
		baseMapper.insert(user);
		//保存用户角色关系
		this.saveUserRoles(user.getId(),user.getRoleLists());
		return findUserById(user.getId());
	}
    //CachePut 保证方法被调用，又希望结果被缓存。
	@Override
	@Caching(evict = {
			@CacheEvict(value = "user", key = "'user_id_'+T(String).valueOf(#user.id)",condition = "#user.id != null and #user.id != 0"),
			@CacheEvict(value = "user", key = "'user_name_'+#user.loginName", condition = "#user.loginName !=null and #user.loginName != ''"),
			@CacheEvict(value = "user", key = "'user_email_'+#user.email", condition = "#user.email != null and #user.email != ''"),
			@CacheEvict(value = "user", key = "'user_tel_'+#user.tel", condition = "#user.tel != null and #user.tel != ''" ),
	})
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public User updateUser(User user) {
		baseMapper.updateById(user);
		//先解除用户跟角色的关系
		this.dropUserRolesByUserId(user.getId());
		this.saveUserRoles(user.getId(),user.getRoleLists());
		return user;
	}

	@Transactional(readOnly = false, rollbackFor = Exception.class)
	@Override
	public void saveUserRoles(Long id, Set<Role> roleSet) {
		baseMapper.saveUserRoles(id,roleSet);
	}

	@Transactional(readOnly = false, rollbackFor = Exception.class)
	@Override
	public void dropUserRolesByUserId(Long id) {
		baseMapper.dropUserRolesByUserId(id);
	}

	@Override
	public int userCount(String param) {
		EntityWrapper<User> wrapper = new EntityWrapper<>();
		wrapper.eq("login_name",param).or().eq("email",param).or().eq("tel",param);
		int count = baseMapper.selectCount(wrapper);
		return count;
	}

	@Transactional(readOnly = false, rollbackFor = Exception.class)
	@Override
	@Caching(evict = {
			@CacheEvict(value = "user", key = "'user_id_'+T(String).valueOf(#user.id)",condition = "#user.id != null and #user.id != 0"),
			@CacheEvict(value = "user", key = "'user_name_'+#user.loginName", condition = "#user.loginName !=null and #user.loginName != ''"),
			@CacheEvict(value = "user", key = "'user_email_'+#user.email", condition = "#user.email != null and #user.email != ''"),
			@CacheEvict(value = "user", key = "'user_tel_'+#user.tel", condition = "#user.tel != null and #user.tel != ''" )
	})
	public void deleteUser(User user) {
		//user.setDelFlag(true);
		user.deleteById();
	}

	/**
	 * 查询用户拥有的每个菜单具体数量
	 * @return
	 */
	@Override
	public Map selectUserMenuCount() {
		return baseMapper.selectUserMenuCount();
	}

}

/*
 * Cache 缓存接口，定义缓存操作。实现有：RedisCache、EhCacheCache、 ConcurrentMapCache等
 * 
 * CacheManager 缓存管理器，管理各种缓存（Cache）组件
 * 
 * @Cacheable 主要针对方法配置，能够根据方法的请求参数对其结果进行缓存
 * 
 * @CacheEvict 清空缓存
 * 
 * @CachePut 保证方法被调用，又希望结果被缓存。
 * 
 * @EnableCaching 开启基于注解的缓存 keyGenerator 缓存数据时key生成策略 serialize 缓存数据时value序列化策略
 */


/*
 * value 缓存的名称，在 spring 配置文件中定义，必须指定 至少一个 例如： @Cacheable(value=”mycache”)
 * 或者 @Cacheable(value={”cache1”,”cache2”} key 缓存的
 * 
 *  key，可以为空，如果指定要按照 SpEL 表达
 * 式编写，如果不指定，则缺省按照方法的所有参数 进行组合 例如： @Cacheable(value=”testcache”,key=”#userName”)
 * 
 * condition 缓存的条件，可以为空，使用 SpEL 编写，返回 true 或者 false，只有为 true 才进行缓存/清除缓存，在
 * 调用方法之前之后都能判断 例如： @Cacheable(value=”testcache”,condition=”#userNam
 * e.length()>2”) 
 * 
 * allEntries (@CacheEvict ) 是否清空所有缓存内容，缺省为 false，如果指定为
 * true，则方法调用后将立即清空所有缓存 例如： @CachEvict(value=”testcache”,allEntries=true)
 * 
 * beforeInvocation (@CacheEvict) 是否在方法执行前就清空，缺省为 false，如果指定 为
 * true，则在方法还没有执行的时候就清空缓存， 缺省情况下，如果方法执行抛出异常，则不会清空 缓存
 * 例如： @CachEvict(value=”testcache”， beforeInvocation=true) 
 * 
 * unless (@CachePut)
 * (@Cacheable) 用于否决缓存的，不像condition，该表达式只在方 法执行之后判断，此时可以拿到返回值result进行判
 * 断。条件为true不会缓存，fasle才缓存 例如： @Cacheable(value=”testcache”,unless=”#result ==
 * null”)
 */